#[cfg(test)]
mod test_chapter3 {
    use std::fmt::Debug;

    // 可变数组类型参数
    #[test]
    fn test_mut_arr() {
        fn reset(arr: &mut [u32]) {
            arr[0] = 5;
            arr[1] = 4;
            arr[2] = 3;
            arr[3] = 2;
            arr[4] = 1;
        }
        let mut arr = [1, 2, 3, 4, 5];
        println!("{:?}", arr);

        reset(&mut arr);
        println!("{:?}", arr);
    }

    // &[u32; 5] 和 &mut [u32] 两种类型的空间占用情况
    #[test]
    fn test_arr_size() {
        assert_eq!(std::mem::size_of::<&[u32; 5]>(), 8);
        assert_eq!(std::mem::size_of::<&mut [u32]>(), 16);
    }

    // 在当前crate 中定义 Add trait
    #[test]
    fn test_add_rhs() {
        trait Add<RHS = Self> {
            type Output;
            fn add(self, rhs: RHS) -> Self::Output;
        }
        impl Add<u64> for u32 {
            type Output = u64;
            fn add(self, other: u64) -> Self::Output {
                (self as u64) + other
            }
        }

        let a = 1u32;
        let b = 2u64;
        assert_eq!(a.add(b), 3);
    }
    // p71 trait 用作抽象类型。此处为 trait 对象的处理方法。
    // 动态分发机制
    #[test]
    fn test_trait_abstract() {
        #[derive(Debug)]
        struct Foo;
        trait Bar {
            fn baz(&self);
        }
        impl Bar for Foo {
            fn baz(&self) {
                println!("{:?}", self);
            }
        }
        fn static_dispatch<T>(t: &T) where T: Bar {
            t.baz();
        }
        // 利用 Bar 这个 trait 对象做参数
        fn dynamic_dispatch(t: &Bar) {
            t.baz();
        }

        let foo = Foo;
        static_dispatch(&foo);
        dynamic_dispatch(&foo);
    }

    // trait 示例
    #[test]
    fn test_trait() {
        struct Duck;
        struct Pig;
        trait Fly {
            fn fly(&self) -> bool;
        }
        impl Fly for Duck {
            fn fly(&self) -> bool {
                true
            }
        }
        impl Fly for Pig {
            fn fly(&self) -> bool {
                false
            }
        }

        fn fly_static<T: Fly>(s: T) -> bool {
            s.fly()
        }
        fn fly_dyn(s: &Fly) -> bool {
            s.fly()
        }

        let pig = Pig;
        assert_eq!(fly_static::<Pig>(pig), false);
        let duck = Duck;
        assert_eq!(fly_static(duck), true);
        assert_eq!(fly_dyn(&Pig), false);
        assert_eq!(fly_dyn(&Duck), true);
    }

    #[test]
    fn test_impl_trait() {
        #[derive(Debug)]
        struct Duck;
        #[derive(Debug)]
        struct Pig;
        trait Fly {
            fn fly(&self) -> bool;
        }
        impl Fly for Duck {
            fn fly(&self) -> bool {
                true
            }
        }
        impl Fly for Pig {
            fn fly(&self) -> bool {
                false
            }
        }

        // 用 impl trait 的方式 重构 sly_static 方法
        fn fly_static_impl(s: impl Fly + Debug) -> bool {
            s.fly()
        }

        fn can_fly(s: impl Fly + Debug) -> impl Fly {
            if s.fly() {
                println!("{:?} can fly", s);
            }else {
                println!("{:?} can't fly", s);
            }
            s
        }

        // 使用 dyn Trait 语法的函数
        fn dyn_can_fly(s: impl Fly + Debug + 'static) -> Box<dyn Fly> {
            if s.fly() {
                println!("{:?} can fly", s);
            }else {
                println!("{:?} can't fly", s);
            }

            Box::new(s)
        }

        let pig = Pig;
        assert_eq!(fly_static_impl(pig), false);
        let duck = Duck;
        assert_eq!(fly_static_impl(duck), true);

        let pig = Pig;
        let pig = can_fly(pig);
        let duck = Duck;
        let duck = can_fly(duck);
    }

    // &'static str 和 &str 互相转换
    #[test]
    fn test_str_as() {
        let a: &'static str = "hello";
        let b: &str = a as &str;
        let c: &'static str = b as &'static str;
    }
}